/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.lang;
import java.lang.ref.*;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

/**
 * This class provides thread-local variables.  These variables differ from
 * their normal counterparts in that each thread that accesses one (via its
 * {@code get} or {@code set} method) has its own, independently initialized
 * copy of the variable.  {@code ThreadLocal} instances are typically private
 * static fields in classes that wish to associate state with a thread (e.g.,
 * a user ID or Transaction ID).
 *该类提供线程本地变量。这些变量与普通的对应变量的不同之处在于，每次访问一个线程(通过其get或set方法)都有自己的、独立初始化的变量副本。
 *ThreadLocal实例通常是类中的私有静态字段，类希望将状态与线程关联(例如，用户ID或事务ID)。
 * <p>For example, the class below generates unique identifiers local to each
 * thread.
 * A thread's id is assigned the first time it invokes {@code ThreadId.get()}
 * and remains unchanged on subsequent calls.
 * 例如，下面的类生成每个线程本地的惟一标识符。线程的id在第一次调用ThreadId.get() 时被分配，并且在后续调用中保持不变。
 * <pre>
 * import java.util.concurrent.atomic.AtomicInteger;
 *
 * public class ThreadId {
 *     // Atomic integer containing the next thread ID to be assigned
 *     private static final AtomicInteger nextId = new AtomicInteger(0);
 *
 *     // Thread local variable containing each thread's ID
 *     private static final ThreadLocal&lt;Integer&gt; threadId =
 *         new ThreadLocal&lt;Integer&gt;() {
 *             &#64;Override protected Integer initialValue() {
 *                 return nextId.getAndIncrement();
 *         }
 *     };
 *
 *     // Returns the current thread's unique ID, assigning it if necessary
 *     public static int get() {
 *         return threadId.get();
 *     }
 * }
 * </pre>
 * <p>Each thread holds an implicit reference to its copy of a thread-local
 * variable as long as the thread is alive and the {@code ThreadLocal}
 * instance is accessible; after a thread goes away, all of its copies of
 * thread-local instances are subject to garbage collection (unless other
 * references to these copies exist).
 *只要线程是活动的并且线程本地实例是可访问的，每个线程都持有对其线程本地变量副本的隐式引用;在线程消失之后，
 *它的所有线程本地实例副本都将受到垃圾收集(除非存在对这些副本的其他引用)。
 * @author  Josh Bloch and Doug Lea
 * @since   1.2
 */
public class ThreadLocal<T> {
    /**
     * ThreadLocals rely on per-thread linear-probe hash maps attached
     * to each thread (Thread.threadLocals and
     * inheritableThreadLocals).  The ThreadLocal objects act as keys,
     * searched via threadLocalHashCode.  This is a custom hash code
     * (useful only within ThreadLocalMaps) that eliminates collisions
     * in the common case where consecutively constructed ThreadLocals
     * are used by the same threads, while remaining well-behaved in
     * less common cases.
     * 线程局部变量依赖于附加到每个线程(线程)的每个线程的线性探测哈希映射。threadlocal和inheritablethreadlocal)。
     * ThreadLocal对象充当键，通过threadLocalHashCode进行搜索。
     * 这是一个自定义哈希代码(仅在ThreadLocalMaps中有用)，它消除了常见情况下的冲突，
     * 即相同的线程使用连续构造的线程局部变量，而在不太常见的情况下保持良好的行为。
     */
    private final int threadLocalHashCode = nextHashCode();

    /**
     * The next hash code to be given out. Updated atomically. Starts at
     * zero.
     * 下一个要给出的哈希码。自动更新。从0开始。
     */
    private static AtomicInteger nextHashCode =
        new AtomicInteger();

    /**
     * The difference between successively generated hash codes - turns
     * implicit sequential thread-local IDs into near-optimally spread
     * multiplicative hash values for power-of-two-sized tables.
     * 连续生成的哈希码之间的差异 - 将隐式顺序线程本地IDs转换为几乎最佳分布的乘法哈希值，用于2次幂表
     */
    /*
     * 可以看出，它是在上一个被构造出的ThreadLocal的ID/threadLocalHashCode的基础上加上一个魔数0x61c88647的。
     * 这个魔数的选取与斐波那契散列有关，0x61c88647对应的十进制为1640531527。斐波那契散列的乘数可以用(long) ((1L << 31) * (Math.sqrt(5) - 1))可以得到2654435769，
     * 如果把这个值给转为带符号的int，则会得到-1640531527。换句话说
	(1L << 32) - (long) ((1L << 31) * (Math.sqrt(5) - 1))得到的结果就是1640531527也就是0x61c88647。
	通过理论与实践，当我们用0x61c88647作为魔数累加为每个ThreadLocal分配各自的ID也就是threadLocalHashCode再与2的幂取模，
	得到的结果分布很均匀。
	ThreadLocalMap使用的是线性探测法，均匀分布的好处在于很快就能探测到下一个临近的可用slot，
	从而保证效率。这就回答了上文抛出的为什么大小要为2的幂的问题。为了优化效率。
	
	对于& (INITIAL_CAPACITY - 1)，相信有过算法竞赛经验或是阅读源码较多的程序员，一看就明白，
	对于2的幂作为模数取模，可以用&(2^n-1)来替代%2^n，位运算比取模效率高很多。至于为什么，因为对2^n取模，
	只要不是低n位对结果的贡献显然都是0，会影响结果的只能是低n位。
     */
    private static final int HASH_INCREMENT = 0x61c88647;

    /**
     * Returns the next hash code.
     * 返回下一个散列代码。
     */
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }

    /**
     * Returns the current thread's "initial value" for this
     * thread-local variable.  This method will be invoked the first
     * time a thread accesses the variable with the {@link #get}
     * method, unless the thread previously invoked the {@link #set}
     * method, in which case the {@code initialValue} method will not
     * be invoked for the thread.  Normally, this method is invoked at
     * most once per thread, but it may be invoked again in case of
     * subsequent invocations of {@link #remove} followed by {@link #get}.
     *返回该线程本地变量的当前线程的“初始值”。此方法将在线程第一次使用get方法访问变量时调用，
     *除非线程之前调用了set方法，在这种情况下，不会为线程调用initialValue方法。
     *通常，每个线程最多调用此方法一次，但如果随后先remove然后get，则可能再次调用此方法。
     * <p>This implementation simply returns {@code null}; if the
     * programmer desires thread-local variables to have an initial
     * value other than {@code null}, {@code ThreadLocal} must be
     * subclassed, and this method overridden.  Typically, an
     * anonymous inner class will be used.
     *这个实现只返回null;如果程序员希望线程局部变量的初始值不是null，则必须子类化ThreadLocal，
     *并覆盖该方法。通常，将使用匿名内部类。
     * @return the initial value for this thread-local
     * 返回这个线程本地的初始值
     */
    protected T initialValue() {
        return null;
    }

    /**
     * Creates a thread local variable. The initial value of the variable is
     * determined by invoking the {@code get} method on the {@code Supplier}.
     *创建线程本地变量。变量的初始值是通过调用供应方上的get方法确定的。
     * @param <S> the type of the thread local's value
     * @param supplier the supplier to be used to determine the initial value
     * @return a new thread local variable
     * @throws NullPointerException if the specified supplier is null
     * @since 1.8
     */
    public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
        return new SuppliedThreadLocal<>(supplier);
    }

    /**
     * Creates a thread local variable.
     * @see #withInitial(java.util.function.Supplier)
     */
    public ThreadLocal() {
    }

    /**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

    /**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     *转换的建立初始化的set方法，定义这个方法为私有方法的原因是以防用户重写了set(),而特意写的一个方法。
     *这个方法目前只会在get（）中调用，初始化ThreadLocalMap并返回初值。
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

    /**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    /**
     * Removes the current thread's value for this thread-local
     * variable.  If this thread-local variable is subsequently
     * {@linkplain #get read} by the current thread, its value will be
     * reinitialized by invoking its {@link #initialValue} method,
     * unless its value is {@linkplain #set set} by the current thread
     * in the interim.  This may result in multiple invocations of the
     * {@code initialValue} method in the current thread.
     *
     * @since 1.5
     */
     public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

    /**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

    /**
     * Create the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the map
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

    /**
     * Factory method to create map of inherited thread locals.
     * Designed to be called only from Thread constructor.
     *
     * @param  parentMap the map associated with parent thread
     * @return a map containing the parent's inheritable bindings
     */
    static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
        return new ThreadLocalMap(parentMap);
    }

    /**
     * Method childValue is visibly defined in subclass
     * InheritableThreadLocal, but is internally defined here for the
     * sake of providing createInheritedMap factory method without
     * needing to subclass the map class in InheritableThreadLocal.
     * This technique is preferable to the alternative of embedding
     * instanceof tests in methods.
     * 方法childValue在子类InheritableThreadLocal中可见，但在此处为内部定义
	        为了提供createInheritedMap工厂方法而没有需要在InheritableThreadLocal中继承map类。
                    该技术优于嵌入的替代方案instanceof测试方法。
     */
    T childValue(T parentValue) {
        throw new UnsupportedOperationException();
    }

    /**
     * An extension of ThreadLocal that obtains its initial value from
     * the specified {@code Supplier}.
     */
    static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {

        private final Supplier<? extends T> supplier;

        SuppliedThreadLocal(Supplier<? extends T> supplier) {
            this.supplier = Objects.requireNonNull(supplier);
        }

        @Override
        protected T initialValue() {
            return supplier.get();
        }
    }

    /**
     * ThreadLocalMap is a customized hash map suitable only for
     * maintaining thread local values. No operations are exported
     * outside of the ThreadLocal class. The class is package private to
     * allow declaration of fields in class Thread.  To help deal with
     * very large and long-lived usages, the hash table entries use
     * WeakReferences for keys. However, since reference queues are not
     * used, stale entries are guaranteed to be removed only when
     * the table starts running out of space.
     * ThreadLocalMap是一个定制的哈希映射，只适合维护线程本地值。在ThreadLocal类之外不导出任何操作。
     * 类是包私有的，允许在类线程中声明字段。为了帮助处理非常大且长期存在的使用，哈希表项对键使用弱引用。
     * 但是，由于没有使用引用队列，因此只有在表开始耗尽空间时才保证删除过时的条目。
     */
    static class ThreadLocalMap {

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         * 这个哈希映射中的条目扩展了WeakReference，使用它的main ref字段作为键
         * (它始终是一个ThreadLocal对象)。注意，null键(即enter .get() == null)意味着该键不再被引用，
         * 因此可以从表中删除该条目。在接下来的代码中，这些条目被称为“陈旧条目”。
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {//当抛弃掉ThreadLocal对象时，垃圾收集器会忽略这个key的引用而清理掉ThreadLocal对象， 防止了内存泄漏
        	 
        	
            /** The value associated with this ThreadLocal. */
            Object value;
         //注意：这里属性不能加入key，否则会导致存在强引用而不能被视为WeakReference回收掉
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

        /**
         * The initial capacity -- MUST be a power of two.
         * 初始容量必须是2的幂。
         */
        private static final int INITIAL_CAPACITY = 16;

        /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         * 根据需要调整表的大小。
         * 表的长度必须总是2的幂。
         */
        private Entry[] table;

        /**
         * The number of entries in the table.
         * 表中的条目（记录）数。
         */
        private int size = 0;

        /**
         * The next size value at which to resize.
         * 要调整大小的下一个大小值。
         * 阈值，目前ThreadLocal的逻辑如下
            if (size >= threshold - threshold / 4)使用较低的阈值加倍，以避免滞后
         */
        private int threshold; // Default to 0

        /**
         * Set the resize threshold to maintain at worst a 2/3 load factor.
         * 设置大小阈值以在最坏情况下保持2/3的负载系数。
         * 在初始化Entry数组时调用
         */
        private void setThreshold(int len) {
            threshold = len * 2 / 3;
        }

        /**
         * Increment i modulo len.
         * 环形意义的下一个索引
         */
        private static int nextIndex(int i, int len) {
            return ((i + 1 < len) ? i + 1 : 0);
        }

        /**
         * Decrement i modulo len.
         * 环形意义的上一个索引
         */
        private static int prevIndex(int i, int len) {
            return ((i - 1 >= 0) ? i - 1 : len - 1);
        }

        /**
         * Construct a new map initially containing (firstKey, firstValue).
         * ThreadLocalMaps are constructed lazily, so we only create
         * one when we have at least one entry to put in it.
         * 首先构造一个包含(firstKey, firstValue)的新映射。
         * ThreadLocalMaps是惰性（懒）构造的，因此我们只在至少有一个条目要放入其中时创建一个。
         */
        ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

        /**
         * Construct a new map including all Inheritable ThreadLocals
         * from given parent map. Called only by createInheritedMap.
         *构造一个新的映射，其中包括来自给定父映射的所有可继承线程局部变量。只能由createInheritedMap调用。
         * @param parentMap the map associated with parent thread.
         */
        private ThreadLocalMap(ThreadLocalMap parentMap) {
            Entry[] parentTable = parentMap.table;
            int len = parentTable.length;
            setThreshold(len);
            table = new Entry[len];

            for (int j = 0; j < len; j++) {
                Entry e = parentTable[j];
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
                    if (key != null) {
                        Object value = key.childValue(e.value);
                        Entry c = new Entry(key, value);
                        int h = key.threadLocalHashCode & (len - 1);
                        while (table[h] != null)
                            h = nextIndex(h, len);
                        table[h] = c;
                        size++;
                    }
                }
            }
        }

        /**
         * Get the entry associated with key.  This method
         * itself handles only the fast path: a direct hit of existing
         * key. It otherwise relays to getEntryAfterMiss.  This is
         * designed to maximize performance for direct hits, in part
         * by making this method readily inlinable.
         *获取与键关联的条目。该方法本身只处理快速路径:直接命中现有键。否则，它将在错过后继续传递。
         *这是为了最大化直接命中的性能而设计的，在某种程度上，这使得这种方法很容易实现。
         * @param  key the thread local object
         * @return the entry associated with key, or null if no such
         */
        private Entry getEntry(ThreadLocal<?> key) {
        	// 根据key这个ThreadLocal的ID来获取索引，也即哈希值
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            /*
             * get数组元素的时候有个很有意思的地方就是快速命中，那么啥意思呢，设计者的思路是啥呢？
             * 20190301理解如下
             * 因为这里是用开放地址法来解决hash冲突的
             * 查询一个键key只会有两种情况，存在元素，或者不存在元素（好像说了 废话）
             * 存在的分2种，如果当前数组没有hash冲突，那么根据key生成的索引值和数组下标一致。
             * 如果当前数组有有hash冲突，且查询的key就是冲突的元素的key，
             * 那么根据key生成的索引值和数组下标不一定一致。
             * 比如有key的值a,b,c,它们根据key.threadLocalHashCode & (table.length - 1)生成
             * 的索引值是一致的设为i,（b、c与a冲突，它们存在a的下标的后面下标）此时只有查询key为a时，才能快速命中，直接返回，
             * 查询b或者c就需要以当前i为起点开始遍历了，以冲突的值遍历遍历完或者找到了元素作为结束的条件。
             * 
             * 其实我想说的一句话就是：
             * 		getEntryAfterMiss方法并不会遍历整个数组，
             * 它是以当前元素为起点，遍历连续非空的元素集合A(因为是根据key来获得索引，如果在A中找不到，那在整个数组中也是没有的),
             * 直到为空或者找到为止。
             * 
             * 还想说一句：
             * 一般查找元素，或者清除元素都是遍历的以当前key生成的下标i为起点的连续非空子集合,并不是整个数组！！！！
             * 貌似只有expungeStaleEntries()方法才会根据数组len进行遍历！！！
             * 
             */
            // 对应的entry存在且未失效且弱引用指向的ThreadLocal就是key，则命中返回
            if (e != null && e.get() == key)//这里e.get()获取的this.referent，就是在Entry构造方法中存入的ThreadLocal<?>
                return e;
            else
                return getEntryAfterMiss(key, i, e);// 因为用的是线性探测，所以往后找还是有可能能够找到目标Entry的。
        }

        /**
         * Version of getEntry method for use when key is not found in
         * its direct hash slot.
         *当键在其直接哈希槽中找不到时使用的getEntry方法的版本。
         * @param  key the thread local object
         * @param  i the table index for key's hash code
         * @param  e the entry at table[i]
         * @return the entry associated with key, or null if no such
         */
        private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
            Entry[] tab = table;
            int len = tab.length;
            // 基于线性探测法不断向后探测直到遇到空entry。
            while (e != null) {
                ThreadLocal<?> k = e.get();
                if (k == key)
                    return e;
                if (k == null)//k==null的情况是remove（）方法标记删除引起的
                    expungeStaleEntry(i);// 该entry对应的ThreadLocal已经被回收，调用expungeStaleEntry来清理无效的entry
                else
                    i = nextIndex(i, len);
                e = tab[i];
            }
            return null;
        }

        /**
         * Set the value associated with key.
         *
         * @param key the thread local object
         * @param value the value to be set
         */
        private void set(ThreadLocal<?> key, Object value) {

            /*
             We don't use a fast path as with get() because it is
              at least as common to use set() to create new entries as
             it is to replace existing ones, in which case, a fast
             path would fail more often than not.
                                      我们没有用get()方法那种的快速定位元素的方式是因为至少我们用set()方法时用来创建新元素和
                                       替换已存在的元素都是一样的常见，在这种情况下，一个快速定位元素的方式（比如创建新元素是很常见的）失败的次数较多。
           getEntry()快速定位的方式如下：
            if (e != null && e.get() == key)
                return e;
            
			*/
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            /*
              set操作涉及到新建和更新操作
              	1.先遍历数组，看能否执行更新元素操作
              	2.无法更新操作就新建元素
             */
            //1.先遍历数组，看能否执行更新元素操作
            //线性探测
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
                /*
                 * 首先要明白一点，一个线程是把threadlocal对象放到map里作为key存储的，
                 * 在一个线程的生命周期里能访问的作用域下均可进行形如：
                 * ThreadLocal<Integer> tl = new ThreadLocal<Integer>();的操作，
                 * 每一个ThreadLocal的对象在执行get()或者set(T)方法时，（如果之前map里不存在key为t1的entry）
                 * 就把它映射到线程的map对象threadlocals中。
                 * 
                 * 
                 * 
                 */
                if (k == key) {//key已存在于当前entry数组中，更新value的值,然后直接结束方法
                    e.value = value;
                    return;
                }

                if (k == null) {//当前的entry是无效的（k为null表示无效数据，需要清除），设置value的值,然后直接结束方法
                	//此时的i下标对应的entry的值是空（null）或者无效的(entry的key为null)
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
            //能够走到这一步，说明当前key不存在entry数组中且在遍历当前连续非空段数据的过程不存在无效数据，此时只有new一个新的元素到数组
            //2.无法更新操作就新建元素，然后cleanSomeSlots(i, sz)再去做启发式清除整个数组的无效数据（如果有的话）
            tab[i] = new Entry(key, value);
            int sz = ++size;
          /*
           * 数组里的元素没有无效数据，并且增加这个元素后数组里存的有效元素个数超过阈值，就rehash
           * 
           * 讲道理，能走到这里来了，我们知道在上面的1中没有无效数据，那么下面的cleanSomeSlots（先找是否存在无效数据
           * ，有就清除，并返回true）能够返回true的唯一可能性就是2中新建的元素的key为null
           * 
           * 多说一句，cleanSomeSlots方法，只会被set(ThreadLocal<?> key, Object value)和
           * replaceStaleEntry(ThreadLocal<?> key, Object value,int staleSlot)方法调用，
           * 其中，replaceStaleEntry只会被set调用，说明只有set操作才会调用cleanSomeSlots方法
           * 
           * 下面的rehash()
           * 重新打包和/或重新调整表的大小。首先扫描整个表，删除过时的条目。
           * 如果这没有充分缩小表的大小，则将表的大小加倍。
           * 执行真正意义上的resize()
           */
          //新增一个新entry后，启发式的删除没有删除元素，并且当前的存在的元素的大小大于等于了阈值，就需要rehash
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
            	/*
            	 * 在rehash方法前，在做最后一次最后的挣扎，来一次全数组的删除无效数据（如果有）
            	 * 然后再判断此时的已存在的元素大小是否大于等3/4的threshold的值，如果是就真正的
            	 * resize()
            	 */
                rehash();
        }

        /**
         * Remove the entry for key.
         * 
         */
        /*
         * 对开放地址法构造的散列表，删除结点不能简单地将被删结 点的空间置为空，否则将截断在它之后填人散列表的同义词结点的查找路径。
         * 这是因为各种开放地址法中，空地址单元（即开放地址）都是查找失败的条件。
         * 因此在用开放地址法处理冲突的散列表上执行删除操作，
         * 只能在被删结点上做删除标记，而不能真正删除结点。
         */
        private void remove(ThreadLocal<?> key) {
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            for (Entry e = tab[i];
                 e != null;//空地址代表搜索结束
                 e = tab[i = nextIndex(i, len)]) {
                if (e.get() == key) {
                    e.clear();//把Entry中当前条目的ThreadLocal引用置空，标记为无效的条目
                    expungeStaleEntry(i);
                    return;
                }
            }
        }

        /**
         * Replace a stale entry encountered during a set operation
         * with an entry for the specified key.  The value passed in
         * the value parameter is stored in the entry, whether or not
         * an entry already exists for the specified key.
         * 将set操作期间遇到的陈旧条目替换为指定键的条目。 无论指定键的条目是否已存在，value参数中传递的值都存储在条目中。
         * As a side effect, this method expunges all stale entries in the
         * "run" containing the stale entry.  (A run is a sequence of entries
         * between two null slots.)
         * 作为副作用，此方法将清除包含陈旧条目的“run”中的所有陈旧条目。 （run是两个空槽之间的一系列条目。）
         * @param  key the key
         * @param  value the value to be associated with key
         * @param  staleSlot index of the first stale entry encountered while
         *         searching for key.搜索键时遇到的第一个陈旧条目的索引。
         */
        private void replaceStaleEntry(ThreadLocal<?> key, Object value,
                                       int staleSlot) {
            Entry[] tab = table;
            int len = tab.length;
            Entry e;

            /*
                Back up to check for prior stale entry in current run.
                We clean out whole runs at a time to avoid continual
             	incremental rehashing due to garbage collector freeing
             	up refs in bunches (i.e., whenever the collector runs).
             	备份以检查当前运行中的先前过时条目。我们一次清理整个运行以避免由于垃圾收集器释放串中的refs（即，每当收集器运行时）不断的增量重新运行。
             */
          /*
           * replaceStaleEntry方法只在set方法中遍历到无效元素时调用
           * 
           * staleSlot为在set方法中遍历时遇到的第一个无效元素的下标
           */
            int slotToExpunge = staleSlot;//记录slotToExpunge，仅仅是为了后面调用expungeStaleEntry(slotToExpunge)来清除连续非空条目的无效数据
            for (int i = prevIndex(staleSlot, len);
                 (e = tab[i]) != null;
                 i = prevIndex(i, len))//以当前无效条目为起点向前遍历非空条目，找到最前面那个无效条目的下标
                if (e.get() == null)
                    slotToExpunge = i;

            // Find either the key or trailing null slot of run, whichever
            // occurs first
            //找到run的key或后续的 null slot，无论哪个首先发生
            for (int i = nextIndex(staleSlot, len);
                 (e = tab[i]) != null;
                 i = nextIndex(i, len)) {//以当前无效条目为起点向后遍历遍历非空条目
            	
            	
                ThreadLocal<?> k = e.get();
                /*
                 If we find key, then we need to swap it
                 with the stale entry to maintain hash table order.
                                                  如果我们找到key，那么我们需要交换它使用陈旧的条目来维护哈希表的顺序。
                 The newly stale slot, or any other stale slot
                 encountered above it, can then be sent to expungeStaleEntry
                 to remove or rehash all of the other entries in run.
                                                  新失效的插槽，或任何其他失效的插槽遇到上面的它，就可以发送到expungeStaleEntry
                                                  删除或重新散列运行中的所有其他项。
                 */

                if (k == key) {
                    e.value = value;
                  //如果我们找到key，那么我们需要交换它使用陈旧的条目来维护哈希表的顺序，交换位置把失效的条目放后面
                    tab[i] = tab[staleSlot];//将下标i的位置赋值为无效（陈旧）的条目
                    tab[staleSlot] = e;//将当前找到的元素放到下标i的前一个位置上

                    // Start expunge at preceding stale entry if it exists
                    /*
                     *slotToExpunge的值是之前的向前遍历非空条目，找到最前那个无效条目的下标
                     */
                    if (slotToExpunge == staleSlot)//表示向前遍历没有无效的条目，slotToExpunge就取下标i，因为下标i的位置就是这个连续非空条目的第一个无效条目
                        slotToExpunge = i;
                    cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);//找到了key就提前在循环里清除了无效条目，后面就直接return，后面代码就不再执行
                    return;
                }

                // If we didn't find stale entry on backward scan, the
                // first stale entry seen while scanning for key is the
                // first still present in the run.
                if (k == null && slotToExpunge == staleSlot)
                    slotToExpunge = i;
            }

            // If key not found, put new entry in stale slot
            //上面的循环后都没有找到key，就重新再堆里创建一个新的条目，然后把当前数组下标的引用指向这个新条目
            tab[staleSlot].value = null;//为了防止内存泄漏，主动将value(即ThreadLocal<T>的T对象)置为null,让gc下次回收时，回收这部分内存
            tab[staleSlot] = new Entry(key, value);

            // If there are any other stale entries in run, expunge them
            if (slotToExpunge != staleSlot)//上面的循环后都没找到key，就在这里做最后的清除无效条目工作。
                cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
        }

        /**
         * Expunge a stale entry by rehashing any possibly colliding entries
         * lying between staleSlot and the next null slot.  This also expunges
         * any other stale entries encountered before the trailing null.  See
         * Knuth, Section 6.4
         *通过重哈希staleSlot和下一个空槽之间的任何可能冲突的条目来删除过时的条目。
         *这还将删除在后面的null之前遇到的任何其他陈旧条目。见Knuth 6.4节
         * @param staleSlot index of slot known to have null key
         * 			已知具有空键的槽的索引
         * @return the index of the next null slot after staleSlot
         * (all between staleSlot and this slot will have been checked
         * for expunging).
         * staleSlot之后的下一个空槽的索引(staleSlot和这个槽之间的所有内容都将被检查是否需要删除)。
         */
        /*
         * 这个函数是ThreadLocal中核心清理函数，它做的事情很简单：
         * 就是从staleSlot开始遍历，将无效（弱引用指向对象被回收）清理，即对应entry中的value置为null，
         * 将指向这个entry的table[i]置为null，直到扫到空entry。
         * 另外，在过程中还会对非空的entry作rehash。
         * 可以说这个函数的作用就是从staleSlot开始清理连续段中的slot（断开强引用，rehash slot等）
         */
        private int expungeStaleEntry(int staleSlot) {
            Entry[] tab = table;
            int len = tab.length;

            // expunge entry at staleSlot
            //清除当前陈旧槽位的条目
         // 因为entry对应的ThreadLocal已经被回收，value设为null，显式断开强引用
            tab[staleSlot].value = null;
         // 显式设置该entry为null，以便垃圾回收
            tab[staleSlot] = null;
            size--;

            // Rehash until we encounter null
            Entry e;
            int i;
          /*
           * 注意：这里我们并不会遍历整个表（只以查询的key生成的下标位置开始遍历连续非空的集合）！！！！
           * 貌似只有expungeStaleEntries()方法才会根据数组len进行遍历！！！
           */
            for (i = nextIndex(staleSlot, len);
                 (e = tab[i]) != null;//空slot(条目)是遍历结束标志
                 i = nextIndex(i, len)) {
                ThreadLocal<?> k = e.get();
                if (k == null) {// 清理对应ThreadLocal已经被回收的entry
                    e.value = null;
                    tab[i] = null;
                    size--;
                } else {
                    int h = k.threadLocalHashCode & (len - 1);
                  /*
                   * 如果 h!=i 表明发生了hash冲突，比如此时元素e的下标根据k.threadLocalHashCode & (len - 1)计算后是4，
                   * 但是4已经有数据了，只能往后面移是5或者6等等。
                   * 所以后面while循环要一直找到那个所在的下标为空的记录，来存放元素e
                   */
                    if (h != i) {//比如此时i为5、6、7...,h=4
                    	/*
                    	 * 下面这段代码的意义：
                    	 * 能进来这个if说明遍历这个for循环前，存在着一段hash冲突的连续的条目，但是可能其中有些条目无效了，在上面的if (k == null) 中已经清空了，
                    	 * 如果清空的这些条目是在这段连续条目的中间，就把后面非空且有效的条目往前移动，使hash冲突的条目连续。
                    	 */
                        tab[i] = null;

                        // Unlike Knuth 6.4 Algorithm R, we must scan until
                        // null because multiple entries could have been stale.
                        //不像《计算机程序设计艺术》）的6.4章节（散列）中的R算法，我们必须扫描直到遇到空的条目，因为多个条目可能已经被标记为无效的，然后在循环时需要清空。
                        /*
                         * 在原代码的这里有句注释值得一提，原注释如下：
                         *
                         * Unlike Knuth 6.4 Algorithm R, we must scan until
                         * null because multiple entries could have been stale.
                         *
                         * 这段话提及了Knuth高德纳的著作TAOCP（《计算机程序设计艺术》）的6.4章节（散列）
                         * 中的R算法。R算法描述了如何从使用线性探测的散列表中删除一个元素。
                         * R算法维护了一个上次删除元素的index，当在非空连续段中扫到某个entry的哈希值取模后的索引
                         * 还没有遍历到时，会将该entry挪到index那个位置，并更新当前位置为新的index，
                         * 继续向后扫描直到遇到空的entry。
                         *
                         * ThreadLocalMap因为使用了弱引用，所以其实每个slot的状态有三种也即
                         * 有效（key未回收），无效（key已回收），空（entry==null）。
                         * 正是因为ThreadLocalMap的entry有三种状态，所以不能完全套高德纳原书的R算法。
                         *
                         * 因为expungeStaleEntry函数在扫描过程中还会对无效slot清理将之转为空slot，
                         * 如果直接套用R算法，可能会出现具有相同哈希值的entry之间断开（中间有空entry）。
                         */
                        while (tab[h] != null)//此时按照上面的假设，h=4,需要将非空且有效的条目往前移动
                            h = nextIndex(h, len);
                        //此时h下标的条目是空的
                        tab[h] = e;
                    }
                }
            }
            return i;//此时下标i的条目是空的
        }

        /**
         * Heuristically scan some cells looking for stale entries.
         * This is invoked when either a new element is added, or
         * another stale one has been expunged. It performs a
         * logarithmic number of scans, as a balance between no
         * scanning (fast but retains garbage) and a number of scans
         * proportional to number of elements, that would find all
         * garbage but would cause some insertions to take O(n) time.
         *启发式地扫描一些单元格，寻找陈旧的条目。在添加新元素或删除另一个陈旧元素时调用此方法。它执行对数次扫描，
         *以平衡不扫描(快速但保留垃圾)和与元素数量成比例的扫描次数，后者将查找所有垃圾，但会导致一些插入花费O(n)时间。
         * @param i a position known NOT to hold a stale entry. The
         * scan starts at the element after i.
         *
         * @param n scan control: {@code log2(n)} cells are scanned,
         * unless a stale entry is found, in which case
         * {@code log2(table.length)-1} additional cells are scanned.
         * When called from insertions, this parameter is the number
         * of elements, but when from replaceStaleEntry, it is the
         * table length. (Note: all this could be changed to be either
         * more or less aggressive by weighting n instead of just
         * using straight log n. But this version is simple, fast, and
         * seems to work well.)
         *
         * @return true if any stale entries have been removed.
         */
        /*
         * 启发式地清理slot,
         * i对应entry是非无效（指向的ThreadLocal没被回收，或者entry本身为空）
         * n是用于控制扫描次数的
         * 正常情况下如果log n次扫描没有发现无效slot，函数就结束了
         * 但是如果发现了无效的slot，将n置为table的长度len，做一次连续段的清理
         * 再从下一个空的slot开始继续扫描
         * 
         * 这个函数有两处地方会被调用，一处是插入的时候可能会被调用，另外个是在替换无效slot的时候可能会被调用，
         * 区别是前者传入的n为元素个数，后者为table的容量
         * 而替换替换无效slot的情况也是在插入的时候被调用的
         * java中一些运算
         * ~ 按位非（NOT）（一元运算）
			& 按位与（AND）
			| 按 位或（OR）
			^ 按位异或（XOR）
			>> 右移
			>>> 右移，左边空出的位以0填 充
			运算符 结果
			<< 左移
			&= 按位与赋值
			|= 按位或赋值
			^= 按 位异或赋值
			>>= 右移赋值
			>>>= 右移赋值，左边空出的位以0填充
			<<= 左 移赋值
         * 对数：
         * 如果a的x次方等于N（a>0，且a不等于1），那么数x叫做以a为底N的对数（logarithm），记作x=logaN。
         * 其中，a叫做对数的底数，N叫做真数。
         * 
         * 注意这里和expungeStaleEntries()方法的区别，expungeStaleEntries会扫描整个entry数组进行
         * 清理无效记录，而这里仅仅是进行log2(n)次的清理，有可能有遗漏的，这仅仅是为了平衡插入花费时间。
         * api里的注释：它执行对数次扫描，以平衡不扫描(快速但保留垃圾)和与元素数量成比例的扫描次数，后者将查找所有垃圾，
         * 但会导致一些插入花费O(n)时间。
         * 一句话就是这里只会清理有限个非空元素段。
         * 模拟entry数组的元素：
          【】 【】【2】 【18】 【4】 【】  【】【】 【】 【】【】 【11】 【27】  【】 【】 【】
			0  1   2     3     4    5    6  7    8   9  10   11    12     13   14  15
			
         */
        private boolean cleanSomeSlots(int i, int n) {
            boolean removed = false;
            Entry[] tab = table;
            int len = tab.length;
            do {
            	// i在任何情况下自己都不会是一个无效slot（只能是有效的或者空的slot），所以从下一个开始判断
                i = nextIndex(i, len);
                Entry e = tab[i];
                if (e != null && e.get() == null) {//扫描的时候如果发现无效slot的时候，就需要重新赋n的值，再扫描整个数组
                    n = len;
                    removed = true;
                    i = expungeStaleEntry(i);//expungeStaleEntry返回一个空的slot
                }
            } while ( (n >>>= 1) != 0);
            return removed;
        }

        /**
         * Re-pack and/or re-size the table. First scan the entire
         * table removing stale entries. If this doesn't sufficiently
         * shrink the size of the table, double the table size.
         * 重新打包和/或重新调整表的大小。首先扫描整个表，删除过时的条目。
         * 如果这没有充分缩小表的大小，则将表的大小加倍。
         */
        private void rehash() {
            expungeStaleEntries();

            // Use lower threshold for doubling to avoid hysteresis
            //使用较低的阈值加倍，以避免滞后
            if (size >= threshold - threshold / 4)
                resize();
        }

        /**
         * Double the capacity of the table.
         * 
         * 这里resize()的时候做的没有HashMap精致，
         * HashMap还判断了超过int最大值了就不能扩容了的判断，是因为
         * HashMap中resize()需要返回节点数组，而这里不用
         */
        private void resize() {
            Entry[] oldTab = table;
            int oldLen = oldTab.length;
            int newLen = oldLen * 2;
            Entry[] newTab = new Entry[newLen];
            int count = 0;

            for (int j = 0; j < oldLen; ++j) {
                Entry e = oldTab[j];
                if (e != null) {
                    ThreadLocal<?> k = e.get();
                    if (k == null) {
                        e.value = null; // Help the GC
                    } else {
                        int h = k.threadLocalHashCode & (newLen - 1);
                        while (newTab[h] != null)
                            h = nextIndex(h, newLen);
                        newTab[h] = e;
                        count++;
                    }
                }
            }

            setThreshold(newLen);
            size = count;
            table = newTab;
        }

        /**
         * Expunge all stale entries in the table.
         * 注意：
         * 这个方法只会在reHash()方法里调用，就是resize前把整个表的无效数据清除，这样保证了resize前的entry数组
         * 里非空的元素都是有效数据
         */
        private void expungeStaleEntries() {
            Entry[] tab = table;
            int len = tab.length;
            for (int j = 0; j < len; j++) {
                Entry e = tab[j];
                if (e != null && e.get() == null)
                    expungeStaleEntry(j);
            }
        }
    }

}
